import { Injectable } from '@nestjs/common';
import { CreateRoleDto } from './dto/create-role.dto';
import { UpdateRoleDto } from './dto/update-role.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { SysRole } from './entities/role.entity';
import { In, Repository, TypeORMError } from 'typeorm';
import { IdsDto } from '@/common/dto/ids.dto';
import { SearchDto } from '@/common/dto/base-search.dto';
import { queryBuilderAndWhereLike } from '@/common/utils/db.andwhere';
import { plainToInstance } from 'class-transformer';
import { ResultRoleConverterDto } from './dto/result-converter.dto';
import { SysMenu } from '../menus/entities/menu.entity';

@Injectable()
export class RolesService {
  constructor(
    @InjectRepository(SysRole)
    private readonly roleRepository: Repository<SysRole>,
    @InjectRepository(SysMenu)
    private readonly menuRepository: Repository<SysMenu>,
  ) {}
  create(createRoleDto: CreateRoleDto) {
    return this.roleRepository.save(createRoleDto);
  }

  async findAll(query: SearchDto) {
    const page = query.pageNum || 1;
    const size = query.pageSize || 10;

    let queryBuilder = this.roleRepository
      .createQueryBuilder('role')
      .where('1=1');

    const likeProps = {
      'roles.name': query.keywords,
    };
    queryBuilder = queryBuilderAndWhereLike(queryBuilder, likeProps);
    const [data, total]: [SysRole[], number] = await queryBuilder
      .skip((page - 1) * size)
      .take(size)
      .getManyAndCount();
    return {
      list: plainToInstance(ResultRoleConverterDto, data),
      total,
    };
  }

  findOne(id: string, showMenu = false) {
    return this.roleRepository.findOne({
      relations: { sysMenus: showMenu },
      where: { id },
    });
  }

  update(id: string, updateRoleDto: UpdateRoleDto) {
    return this.roleRepository.update(id, updateRoleDto);
  }

  remove({ ids }: IdsDto) {
    return this.roleRepository.delete({ id: In(ids.split(',')) });
  }

  getOptions() {
    return this.roleRepository
      .createQueryBuilder('roles')
      .select('id', 'value')
      .addSelect('name', 'label')
      .getRawMany();
  }

  updateStatus(id: string, status: number) {
    return this.roleRepository.update(id, { status });
  }

  async updateRoleMenus(id: string, menuIds: string[]) {
    const menus = await this.menuRepository.find({
      where: { id: In(menuIds) },
    });
    const role = await this.findOne(id);
    if (!role) {
      throw new TypeORMError('角色不存在');
    }
    role.sysMenus = menus;
    await this.roleRepository.save(role);
    return '绑定成功';
  }

  async getRoleMenuIds(id: string) {
    const role = await this.findOne(id, true);
    if (!role) {
      throw new TypeORMError('角色不存在');
    }
    return role.sysMenus.map((item) => Number(item.id));
  }
}
